import { DeleteOutlined, PlusOutlined, SettingOutlined } from '@ant-design/icons';
import { App, Button } from 'antd';
import React, { useMemo, useState } from 'react';
import { NodeProps } from 'reactflow';
import { useContextSelector } from 'use-context-selector';

import CollapsibleSection from '@/components/CollapsibleSection';
import Tables from '@/components/tables/tables';
import { t } from '@/locales/i18n';
import { getNanoid } from '@/pages/chat/tools/tools';
import {
  FlowNodeOutputTypeEnum,
  NodeInputKeyEnum,
  WorkflowIOValueTypeEnum,
} from '@/types/workflow/constant';
import { FlowNodeInputItemType, FlowNodeOutputItemType } from '@/types/workflow/io';
import { FlowNodeItemType } from '@/types/workflow/node';
import { ContextExtractAgentItemType } from '@/types/workflow/template/system/contextExtract/type';

import { WorkflowContext } from '../../../context';
import NodeCard from '../render/NodeCard';
import RenderInput from '../render/RenderInput';
import RenderOutput from '../render/RenderOutput';
import RenderToolInput from '../render/RenderToolInput';

import ExtractFieldModal, { defaultField } from './ExtractFieldModal';

const NodeExtract = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
  const { inputs, outputs, nodeId } = data;
  const { message } = App.useApp();

  const [expandedSections, setExpandedSections] = useState<Set<'output' | 'input' | 'params'>>(
    new Set(['input']),
  );

  const toggleSection = (section: 'output' | 'input' | 'params') => {
    setExpandedSections((prev) => {
      const newSet = new Set(prev);
      if (newSet.has(section)) {
        newSet.delete(section);
      } else {
        newSet.add(section);
      }
      return newSet;
    });
  };

  const { onChangeNode, splitToolInputs } = useContextSelector(WorkflowContext, (ctx) => ctx);

  // const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
  const { isTool, commonInputs } = useMemo(() => {
    return splitToolInputs && splitToolInputs(inputs, nodeId);
  }, [splitToolInputs, inputs, nodeId]);

  const filterHiddenInputs = commonInputs.filter((item) => true);
  const requiredInputs = filterHiddenInputs.filter((item) => item.required);
  const optionalInputs = filterHiddenInputs.filter((item) => !item.required);

  const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>();

  const CustomComponent = useMemo(
    () => ({
      [NodeInputKeyEnum.extractKeys]: ({
        value: extractKeys = [],
        ...props
      }: Omit<FlowNodeInputItemType, 'value'> & {
        value?: ContextExtractAgentItemType[];
      }) => {
        const columns = [
          {
            title: t('item_name'),
            dataIndex: 'key',
          },
          {
            title: t('item_description'),
            dataIndex: 'desc',
            render: (text: string) => text || '-',
          },
          {
            title: t('required'),
            dataIndex: 'required',
            width: 80,
            render: (required: boolean) => (required ? '✅' : ''),
          },
          {
            title: t('operations'),
            width: 100,
            render: (_: any, record: ContextExtractAgentItemType) => (
              <div className="flex">
                <Button
                  type="text"
                  icon={<SettingOutlined />}
                  onClick={() => setEditExtractField(record)}
                />
                <Button
                  type="text"
                  danger
                  icon={<DeleteOutlined />}
                  onClick={() => {
                    onChangeNode({
                      nodeId,
                      type: 'updateInput',
                      key: NodeInputKeyEnum.extractKeys,
                      value: {
                        ...props,
                        value: extractKeys.filter((extract) => record.key !== extract.key),
                      },
                    });

                    onChangeNode({
                      nodeId,
                      type: 'delOutput',
                      key: record.key,
                    });
                  }}
                />
              </div>
            ),
          },
        ];

        return (
          <div>
            <div className="flex items-center">
              <div className="font-medium">{t('core.module.extract.Target field')}</div>
              <Button
                type="text"
                className="ml-auto"
                icon={<PlusOutlined />}
                onClick={() => setEditExtractField(defaultField)}
              />
            </div>
            <div className="overflow-hidde mt-2">
              <Tables dataSource={extractKeys} columns={columns} paginationHide />
            </div>
          </div>
        );
      },
    }),
    [nodeId, onChangeNode],
  );

  const render = useMemo(() => {
    return (
      <NodeCard selected={selected} minW="400px" {...data}>
        <div className="flex flex-col gap-3 space-y-0">
          <CollapsibleSection
            title={t('workflow.node.basic_config')}
            subtitle={t('workflow.node.basic_config_desc')}
            isExpanded={expandedSections.has('input')}
            onToggle={() => toggleSection('input')}
            type="input"
          >
            {isTool && <RenderToolInput nodeId={nodeId} inputs={inputs} />}

            <RenderInput nodeId={nodeId} flowInputList={requiredInputs} />
          </CollapsibleSection>

          <CollapsibleSection
            title={t('workflow.node.variable_config')}
            subtitle={t('workflow.node.variable_config_desc')}
            isExpanded={expandedSections.has('params')}
            onToggle={() => toggleSection('params')}
            type="params"
          >
            <div className="space-y-2">
              {optionalInputs.length > 0 && (
                <RenderInput
                  nodeId={nodeId}
                  flowInputList={optionalInputs}
                  CustomComponent={CustomComponent}
                />
              )}
            </div>
          </CollapsibleSection>

          <CollapsibleSection
            title={t('workflow.node.output')}
            subtitle={t('workflow.node.output_desc')}
            isExpanded={expandedSections.has('output')}
            onToggle={() => toggleSection('output')}
            type="output"
            className="pb-3"
          >
            {outputs.filter((output) => output.type !== FlowNodeOutputTypeEnum.hidden).length >
              0 && (
              <div className="px-2">
                <RenderOutput nodeId={nodeId} flowOutputList={outputs} />
              </div>
            )}
          </CollapsibleSection>
        </div>

        {!!editExtractFiled && (
          <ExtractFieldModal
            defaultField={editExtractFiled}
            onClose={() => setEditExtractField(undefined)}
            onSubmit={(data) => {
              if (data.key.trim() === '') {
                message.warning(t('字段名是必须的'));
                return;
              }
              const input = inputs.find(
                (input) => input.key === NodeInputKeyEnum.extractKeys,
              ) as FlowNodeInputItemType;
              const extracts: ContextExtractAgentItemType[] = input.value || [];

              const exists = extracts.find((item) => item.key === editExtractFiled.key);

              const newInputs = exists
                ? extracts.map((item) => (item.key === editExtractFiled.key ? data : item))
                : extracts.concat(data);

              onChangeNode({
                nodeId,
                type: 'updateInput',
                key: NodeInputKeyEnum.extractKeys,
                value: {
                  ...input,
                  value: newInputs,
                },
              });

              const newOutput: FlowNodeOutputItemType = {
                id: getNanoid(),
                key: data.key,
                label: `${t('extraction_results')}-${data.desc}`,
                valueType: data.valueType || WorkflowIOValueTypeEnum.string,
                type: FlowNodeOutputTypeEnum.static,
              };

              if (exists) {
                if (editExtractFiled.key === data.key) {
                  const output = outputs.find(
                    (output) => output.key === data.key,
                  ) as FlowNodeOutputItemType;

                  // update
                  onChangeNode({
                    nodeId,
                    type: 'updateOutput',
                    key: data.key,
                    value: {
                      ...output,
                      valueType: newOutput.valueType,
                      label: newOutput.label,
                    },
                  });
                } else {
                  onChangeNode({
                    nodeId,
                    type: 'replaceOutput',
                    key: editExtractFiled.key,
                    value: newOutput,
                  });
                }
              } else {
                onChangeNode({
                  nodeId,
                  type: 'addOutput',
                  value: newOutput,
                });
              }

              setEditExtractField(undefined);
            }}
          />
        )}
      </NodeCard>
    );
  }, [
    selected,
    data,
    expandedSections,
    isTool,
    nodeId,
    inputs,
    requiredInputs,
    optionalInputs,
    CustomComponent,
    outputs,
    editExtractFiled,
    onChangeNode,
    message,
  ]);

  return render;
};

export default React.memo(NodeExtract);
